flake8-class-attributes-orderで変数やメソッドの定義順を統一しよう!
CX事業本部@大阪の岩田です。
私が現在関わっている案件は何度かメンバーの入れ替わりがあり、コーディング規約が微妙に統一できていない部分がありました。具体的には以下のようにパブリックなメソッドとプライベートなメソッドの定義がゴチャゴチャと混在している状況でした。
class SomeClass: def __private_method1(): print('pprivate method 1') def public_method1(): print('public method 1') @staticmethod def static_method1(): print('static method 1') def public_method2(): print('public method 2') def __private_method2(): print('pprivate method 2') @staticmethod def static_method2(): print('static method 2')
後々の保守性を考えるとプライベートメソッドはプライベートメソッドでまとめて定義し、パブリックメソッドはパブリックメソッドでまとめて定義したいところです。対策のためにflake8のプラグインflake8-class-attributes-orderを導入してみたので利用方法等ご紹介します。
flake8-class-attributes-orderとは?
その名の通りクラスの属性(コンストラクタ、変数、メソッド等広い意味での属性)の定義順をチェックし、規約通りに定義されていない場合に警告してくれるflake8のプラグインす。開発元はロシア企業のBestDoctor社で、GitHubのリポジトリはこちらです。
https://github.com/best-doctor/flake8-class-attributes-order
やってみる
実際に試してみましょう。なお、今回使用した環境は以下の通りです。
- Python: 3.7
- flake8-class-attributes-order: v0.1.0
まずはpipを使ってflake8-class-attributes-orderをインストールします。
$ pip install flake8-class-attributes-order
これで依存関係のあるflake8もまとめてインストールされます。インストールできたら先程のクラス定義をチェックしてみます。
$ flake8 sample.py
チェックが完了すると以下のように警告が出力されます
sample.py:3:5: CCE001 SomeClass.__private_method1 should be after SomeClass.public_method1 sample.py:6:5: CCE001 SomeClass.public_method1 should be after SomeClass.static_method1 sample.py:16:5: CCE001 SomeClass.__private_method2 should be after SomeClass.static_method2
出力されたメッセージに従って、クラスの定義を以下のように書き換えてみます。
class SomeClass: @staticmethod def static_method1(): print('static method 1') @staticmethod def static_method2(): print('static method 2') def public_method1(): print('public method 1') def public_method2(): print('public method 2') def __private_method1(): print('pprivate method 1') def __private_method2(): print('pprivate method 2')
この状態で再度チェックにかけてみます。
$ flake8 sample2.py
今度は警告無しでチェックが完了します。
設定など
デフォルトの設定
flake8-class-attributes-orderをデフォルトのまま使用すると、クラスの属性が以下の順序になっていることをチェックします。
__new__
__init__
__post_init__
- その他のマジックメソッド
- プロパティ
- スタティックメソッド
- クラスメソッド
- その他のメソッド
- プライベートなメソッド
Strict mode
さらにStrict modeという組み込みのルールを利用することで
__new__
__init__
__post_init__
- その他のマジックメソッド
- プロパティ
- スタティックメソッド
- クラスメソッド
- その他のメソッド
- プライベートな プロパティ
- プライベートなスタティックメソッド
- プライベートなクラスメソッド
- その他のプライベートなメソッド
の順序になっていることをチェックできます。Strict modeによるチェックは
$ flake8 --use-class-attributes-order-strict-mode sample.py
のように--use-class-attributes-order-strict-mode
オプションを付与することで実行可能です。もしくは.flake8
に以下のように記述しておくことで、オプションの指定を省略することも可能です。
[flake8] use_class_attributes_order_strict_mode = True
独自ルールの定義
デフォルトの設定やStrict modeとは異なるルールでチェックをかけたい場合は、独自ルールを定義することも可能です。独自ルールの定義は--class-attributes-order
オペションにクラスの属性をカンマ区切りで渡すことで定義可能です。
$ flake8 --class-attributes-order=private_method,method,static_method <sample2></sample2>.py
この例では
- プライベートメソッド
- その他メソッド
- スタティックメソッド
の順番になるような独自ルールを指定しています。この独自ルールでチェックを実行すると結果は以下のようになります。
sample2.py:7:5: CCE001 SomeClass.static_method2 should be after SomeClass.public_method1 sample2.py:14:5: CCE001 SomeClass.public_method2 should be after SomeClass.__private_method1
先程はチェックOKだったsample2.pyがNGに変わったことが分かります。
独自ルールの定義で指定可能な属性はREADMEに記載されているので、詳細についてはREADMEを参照してみて下さい。メタクラスやネステッドクラス等の順序まで指定可能です。なお、独自ルールの定義についてもその他のオプションと同様に.flake8
に設定を記述しておくことが可能です。.flake8
を利用する場合は以下のように設定します。
[flake8] class_attributes_order = field, meta_class, nested_class, magic_method, property_method, static_method, class_method, method, private_method
注意点
現在flake8-class-attributes-orderの最新版はv0.1.0ですが、__new__
や__str__
などの特殊メソッドに関するエラーメッセージが正しく生成されないという不具合があります。
例えば
class A: def foo(self): pass def __init__(self): pass
というクラス定義に対してチェックを実行すると
CCE001 A.foo should be after A.__init__
というエラーメッセージが出力されるのが期待値ですが、実際のエラーメッセージは
CCE001 A.foo should be after A.None
となります。
こちらのプルリクで修正は完了しているので、新バージョンがリリースされるのを待ちましょう。
まとめ
flake8-class-attributes-orderのご紹介でした。その他のflake8のプラグインと併用しつつ、Gitのpre-commit hookで自動チェックすることでソースコードの保守性が担保できそうです。以下の記事も参考にしつつ、是非試して見て下さい。